/**
 * Created by rex on 2015/8/7.
 */
class Notice{
    private title_div:any;
    private body_div:any;
    private dialog_div:any;
    private box:any;
    private mask:any;
    private btn_div:any;
    private btn_ok:any;
    private btn_cancel:any;
    private input:any;
    private input_div:any;
    private msg_div:any;
    private notice_msg_div:any;
    private mode:string = "OK";
    private msg_mode:string = "FINE";
    private msg_time:number = 1000;

    private result_confirm:boolean = false;
    private result_prompt:string = "";

    private ok_callback:any = null;
    private cancel_callback:any = null;
    private keyup_event:any = null;
    private mask_click_event:any = null;

    private guid:number;
    public static zIndex:number = 2000;
    private static zStep:number = 10;

    private title:string = "";
    private content:string = "";
    private draggable:boolean = false;

    private notifications:NotificationElement[]=[];

    constructor(mode:string, option:any){
        // msg mode
        if(mode == "MSG"){
            this.mode = "MSG";
            this.content = option.content;
            this.msg_mode = option.msg_type;
            this.msg_time = option.time;
            this.showMsg();
            return;
        }else if(mode == "Notification"){
            this.drawNotification(option);
            return;
        }

        // modal box mode
        if(option.title){
            this.title = this.htmlEncode(option.title);
        }
        if(option.content){
            this.content = option.content;
        }
        if(option.draggable){
            this.draggable = option.draggable;
        }
        if(mode.trim().length > 0){
            this.mode = mode;
        }
        if(option.ok_callback){
            this.ok_callback = option.ok_callback;
        }
        if(option.cancel_callback){
            this.cancel_callback = option.cancel_callback;
        }

        this.drawFrame();
        this.showMask();
        this.showBox();
    }

    private drawFrame(){
        // increase zIndex
        this.guid = Notice.zIndex;
        Notice.zIndex += Notice.zStep;

        this.title_div = document.createElement("div");
        this.body_div = document.createElement("div");
        this.input_div = document.createElement("div");
        this.input = document.createElement("input");
        this.btn_div = document.createElement("div");
        this.btn_ok = document.createElement("button");
        this.btn_cancel = document.createElement("button");

        this.title_div.innerHTML = this.htmlEncode(this.title);
        this.body_div.innerHTML = this.content;
        this.btn_ok.innerHTML = "确认";
        this.btn_cancel.innerHTML = "取消";

        var content_div:any = document.createElement("div");
        this.dialog_div = document.createElement("div");
        this.box = document.createElement("div");
        this.mask = document.createElement("div");

        this.addClass(this.title_div, "notice-header");
        this.addClass(this.body_div, "notice-body");
        this.addClass(this.btn_div, "notice-btn-group");
        this.addClass(this.btn_ok, "notice-btn-ok");
        this.addClass(this.btn_cancel, "notice-btn-cancel");
        this.addClass(content_div, "notice-content");
        this.addClass(this.dialog_div, "notice-dialog");
        this.addClass(this.box, "notice-box");

        // group btns
        this.btn_div.appendChild(this.btn_ok);
        if(this.mode == "YN" || this.mode == "PROMPT"){
            this.btn_div.appendChild(this.btn_cancel);
        }

        content_div.appendChild(this.title_div);
        content_div.appendChild(this.body_div);
        if(this.mode == "PROMPT"){
            this.addClass(this.input, "notice-prompt-input");
            this.input_div.appendChild(this.input)
            this.addClass(this.input_div, "notice-input-div");
            content_div.appendChild(this.input_div);
        }

        content_div.appendChild(this.btn_div);
        this.dialog_div.appendChild(content_div);
        this.box.appendChild(this.dialog_div);

        this.box.setAttribute("id", "Notice-"+this.guid);

        document.body.appendChild(this.box);
        document.body.appendChild(this.mask);
    }

    private showMask(){
        this.mask.style.position = "fixed";
        this.mask.style.top = "0";
        this.mask.style.right = "0";
        this.mask.style.bottom = "0";
        this.mask.style.left = "0";
        this.mask.style.zIndex = ""+this.guid;
        this.mask.style.backgroundColor = "#000";
        this.mask.style.opacity = ".5";
    }

    private hideMask(){
        this.mask.style.display = "none";
    }

    private showBox(){
        // set box div style
        this.box.style.zIndex = this.guid + 1;
        this.box.style.display = "block";
        this.box.style.position = "absolute";
        this.box.style.width = "100%";
        this.box.style.top = "10%";
        // set dialog div style
        this.dialog_div.style.margin = "0 auto";
            //this.dialog_div.style.width = "690px";
            //this.dialog_div.style.background = "#FFF";
        this.dialog_div.style.opacity = "1";
        // set title div style
            //this.title_div.style.textAlign = "center";
            //this.title_div.style.fontWeight = "bold";
            //this.title_div.style.fontSize = "16px";
            //this.title_div.style.padding = "10px";
        // set body div style
            //this.body_div.style.padding = "10px";
        // set btn group div style
        this.btn_div.style.textAlign = "center";
        this.btn_div.style.padding = "10px";

        // binding events
        this.bindBtnsEvent();
    }

    private hideBox(){
        this.box.style.display = "none";
    }

    private bindBtnsEvent(){
        var _this = this;

        this.mask_click_event = function(e){
            if(e.target == _this.mask || e.target == _this.box){
                _this.destroyBox();
                _this.result_confirm = false;
                if(_this.mode == "OK"){
                    if(_this.ok_callback){
                        _this.ok_callback();
                    }
                }else{
                    if(_this.cancel_callback){
                        _this.cancel_callback();
                    }
                }
            };
        }

        this.keyup_event = function (e) {
            if(e.keyCode == 27){
                _this.destroyBox();
                _this.result_confirm = false;
                if(_this.mode == "OK"){
                    if(_this.ok_callback){
                        _this.ok_callback();
                    }
                }else{
                    if(_this.cancel_callback){
                        _this.cancel_callback();
                    }
                }
            }
        };

        document.addEventListener("click", this.mask_click_event);

        if(this.mode == "YN"){
            this.btn_cancel.addEventListener("click", function (e) {
                _this.destroyBox();
                _this.result_confirm = false;
                if(_this.cancel_callback){
                    _this.cancel_callback();
                }
            });

            this.btn_ok.addEventListener("click", function (e) {
                _this.destroyBox();
                _this.result_confirm = true;
                if(_this.ok_callback){
                    _this.ok_callback();
                }
            });

            document.addEventListener("keyup", this.keyup_event);
        }else if(this.mode == "PROMPT"){
            this.btn_ok.addEventListener("click", function (e) {
                _this.destroyBox();
                _this.result_prompt = _this.input.value;
                if(_this.ok_callback){
                    _this.ok_callback(_this.result_prompt);
                }
            });
            this.btn_cancel.addEventListener("click", function (e) {
                _this.destroyBox();
                _this.result_prompt = "";
                if(_this.cancel_callback){
                    _this.cancel_callback();
                }
            });
            document.addEventListener("keyup", this.keyup_event);
        }else{
            this.btn_ok.addEventListener("click", function (e) {
                _this.destroyBox();
                _this.result_confirm = true;
                if(_this.ok_callback){
                    _this.ok_callback();
                }
            });
            document.addEventListener("keyup", this.keyup_event);
        }
    }

    private destroyBox(){
        this.hideBox();
        this.hideMask();
        this.removeAllChildRecycle(this.box);
        this.removeAllChildRecycle(this.mask);
        document.removeEventListener("keyup", this.keyup_event);
        document.removeEventListener("click",this.mask_click_event);
    }

    /**
     * 展示提示信息
     */
    private showMsg(){
        var _this = this;
        this.msg_div = document.createElement("div");
        this.notice_msg_div = document.createElement("div");
        this.msg_div.innerHTML = this.htmlEncode(this.content);
        this.addClass(this.msg_div, "notice-msg");
        this.addClass(this.notice_msg_div, "notice-msg-box");
        this.addClass(this.notice_msg_div, "notice-" + this.msg_mode.toLowerCase());
        this.notice_msg_div.appendChild(this.msg_div);
        this.notice_msg_div.style.zIndex = Notice.zIndex;
        //this.msg_div.style.width = "960px";
        //this.msg_div.style.margin = "0 auto";
        //this.msg_div.style.textAlign = "center";
        this.notice_msg_div.style.position = "fixed";
        this.notice_msg_div.style.width = "100%";
        Notice.zIndex += Notice.zStep;

        var child_nodes = document.body.childNodes;
        if(child_nodes.length>0){
            var child = child_nodes[0];
            document.body.insertBefore(this.notice_msg_div,child);
        }else{
            document.body.appendChild(this.notice_msg_div);
        }


        // set timer
        //alert(_this.msg_time);
        var timer = window.setTimeout(function (e) {
            _this.hideMsg();
            window.clearTimeout(timer);
            //alert("asdf");
        },_this.msg_time);
    }

    /**
     * 消失提示信息
     */
    private hideMsg(){
        this.removeAllChildRecycle(this.notice_msg_div);
    }

    /**
     * 删除子节点
     * @param div
     */
    private removeAllChild(ele:any){
        while(ele.hasChildNodes()){
            ele.removeChild(ele.firstChild);
        }
    }

    /**
     * 移除节点递并归移除子节点
     * @param div
     */
    private removeAllChildRecycle(ele:any){
        while(ele.hasChildNodes()){
            this.removeAllChildRecycle(ele.firstChild);
        }
        this.removeNode(ele);
    }

    /**
     * 添加类
     * @param dom
     * @param className
     */
    private addClass(dom:any, className:string){
        var old_class_name = dom.className;
        var new_class_name:string;
        var arr = old_class_name.split(/ +/);
        new_class_name = "";
        arr.push(className);
        for(var idx in arr){
            var ele = arr[idx];
            if(ele != ""){
                new_class_name = new_class_name + ele + " ";
            }
        }
        new_class_name = new_class_name.trim();
        dom.className = new_class_name
    }

    /**
     * 移除类
     * @param dom
     * @param className
     */
    private removeClass(dom:any, className:string){
        var old_class_name = dom.className;
        var new_class_name:string = "";
        var arr = old_class_name.split(/ +/);

        for(var idx in arr){
            var ele = arr[idx];
            if(ele != className && ele != ""){
                new_class_name = new_class_name + ele + " ";
            }
        }
        new_class_name = new_class_name.trim();
        dom.className = new_class_name
    }

    /**
     * 封装移除dom节点
     * @param element
     */
    private removeNode(element:any){
        if(element.remove){
            element.remove();
        }else if(element.removeNode){
            element.removeNode();
        }else{
            element.outerHTML = "";
        }
    }

    /**
     * html转码
     * @param str
     * @returns {string}
     */
    private htmlEncode(str){
        var s = "";
        if (str.length == 0) return "";
        s = str.replace(/&/g, "&amp;");
        s = s.replace(/</g, "&lt;");
        s = s.replace(/>/g, "&gt;");
        return s;
    }

    public static alert(option:{title:string; content:string; ok_callback:any; draggable:boolean}):void{
        if(!option){
            throw Error('需要参数 option:{title:string; content:string; ok_callback:any; draggable:boolean}');
        }
        new Notice("OK", option);
    }

    public static confirm(option:{title:string; content:string; ok_callback:any; cancel_callback:any; draggable:boolean}):void{
        if(!option){
            throw Error('需要参数 option:{title:string; content:string; ok_callback:any; cancel_callback:any; draggable:boolean}');
        }
        new Notice("YN", option);
    }

    public static prompt(option:{title:string; content:string; ok_callback:any; cancel_callback:any; draggable:boolean}):void{
        if(!option){
            throw Error('需要参数 option:{title:string; content:string; ok_callback:any; cancel_callback:any; draggable:boolean}');
        }
        new Notice("PROMPT", option);
    }

    public static msg(option:{message:string; mode:string; time:number}){
        if(!option){
            throw Error('需要参数 option:{message:string; mode:string; time:number}');
        }
        var new_option:any = {};
        if(option.message){
            new_option.content = option.message;
        }else{
            new_option.content = "";
        }
        if(option.time){
            new_option.time = option.time;
        }else{
            new_option.time = 1000;
        }

        if(option.mode && option.mode.length > 0){
            if(option.mode.trim()=="FINE" || option.mode.trim()=="ERROR" || option.mode.trim()=="WARN"){
                new_option.msg_type = option.mode
            }else{
                new_option.msg_type = "FINE";
            }
        }else{
            new_option.msg_type = "FINE";
        }

        new Notice("MSG", new_option);
    }

    public static notification(option:{title:string;icon:string;body:string;redirect:string}){
        var notification: any;
        if(typeof(Notification) != "undefined"){
            if(Notification.permission != "granted"){
                Notification.requestPermission();
                new Notice("Notification",option);
            }else{
                notification = new Notification(option.title,{icon:option.icon,body:option.body});
                if(option.redirect){
                    notification.onclick = function(e){
                        window.open(option.redirect);
                    }
                }
            }
        }else{
            new Notice("Notification",option);
        }
    }

    private drawNotification(option:{title:string;icon:string;body:string;redirect:string}):NotificationElement{
        var notification:NotificationElement = {
            id:0,
            frame:HTMLDivElement = null,
            close_btn:HTMLSpanElement = null,
            icon_div:HTMLDivElement = null,
            msg_div:HTMLDivElement = null,
            icon_img:HTMLImageElement = null,
            title_span:HTMLSpanElement = null,
            body_span:HTMLSpanElement = null,
            from_span:HTMLSpanElement = null
        };
        notification.frame = document.createElement("div");
        this.addClass(notification.frame,"notice-notification");

        notification.close_btn = document.createElement("span");
        notification.close_btn.innerHTML = "x";
        this.addClass(notification.close_btn,"notice-notification-close")
        // add event listener
        var _this = this;
        notification.close_btn.addEventListener("click", function (e) {
            _this.removeAllChildRecycle(notification.frame);
        });

        // icon box
        notification.icon_div = document.createElement("div");
        this.addClass(notification.icon_div,"notice-notification-icon");

        notification.icon_img = document.createElement("img");
        if(option.icon.length>0){
            notification.icon_img.setAttribute("src",option.icon);
        }
        notification.icon_div.appendChild(notification.icon_img);

        // msg box
        notification.msg_div = document.createElement("div");
        this.addClass(notification.msg_div,"notice-notification-msg");

        notification.title_span = document.createElement("span");
        notification.title_span.innerHTML = this.htmlEncode(option.title);
        this.addClass(notification.title_span,"notice-notification-msg-title");

        notification.body_span = document.createElement("span");
        notification.body_span.innerHTML = this.htmlEncode(option.body);
        this.addClass(notification.body_span,"notice-notification-msg-body");

        notification.from_span = document.createElement("span");
        notification.from_span.innerHTML = this.htmlEncode(window.location.href);
        this.addClass(notification.from_span,"notice-notification-msg-from");

        // put spans into msg
        notification.msg_div.appendChild(notification.title_span);
        notification.msg_div.appendChild(notification.body_span);
        notification.msg_div.appendChild(notification.from_span);

        // put boxs into frame
        notification.frame.appendChild(notification.close_btn);
        notification.frame.appendChild(notification.icon_div);
        notification.frame.appendChild(notification.msg_div);

        notification.id = Notice.zIndex;
        Notice.zIndex = Notice.zIndex + Notice.zStep;
        this.addClass(notification.frame,"notification-ident-" + notification.id.toString());

        // click event
        notification.frame.addEventListener("click", function (e) {
            var target = e.target;
            if(target != notification.close_btn){
                //console.log("you clicked notification");
                _this.removeAllChildRecycle(notification.frame);
                if(option.redirect){
                    if(option.redirect.length > 0){
                        window.open(option.redirect);
                    }

                }
            }
        })

        document.body.appendChild(notification.frame);
        this.notifications.push(notification);

        return notification;
    }
}

declare var Notification;

interface NotificationElement {
    id:number;
    frame:HTMLDivElement;
    close_btn:HTMLSpanElement;
    icon_div:HTMLDivElement;
    msg_div:HTMLDivElement;
    icon_img:HTMLImageElement;
    title_span:HTMLSpanElement;
    body_span:HTMLSpanElement;
    from_span:HTMLSpanElement;
}
